﻿using ProDivingJudge2salmon14;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ProDivingJudge2salmon14
{
    public partial class FormMain : Form, IFormMain
    {
        private List<RadioButton> RootRbtns = new List<RadioButton>();
        private List<RadioButton> ChildRbtns = new List<RadioButton>();
        private NewJudgeForm judge;
        private BackgroundWorker constantWorker = new BackgroundWorker();
        private BackgroundWorker connectWorker = new BackgroundWorker();
        private Size orignSize;
        private List<Image> dots = new List<Image>();

        public FormMain(NewJudgeForm judge)
        {
            InitializeComponent();

            this.judge = judge;
            this.orignSize = new Size(this.Size.Width, this.Size.Height);

            dots.Add(ProDivingJudge2salmon14.Properties.Resources.RedDot);
            dots.Add(ProDivingJudge2salmon14.Properties.Resources.GreenDot1);

            RootRbtns.Add(ScoreRoot1);
            RootRbtns.Add(ScoreRoot2);
            RootRbtns.Add(ScoreRoot3);
            RootRbtns.Add(ScoreRoot4);
            RootRbtns.Add(ScoreRoot5);
            RootRbtns.Add(ScoreRoot6);
            RootRbtns.Add(ScoreRoot7);

            ChildRbtns.Add(ScoreOpt1);
            ChildRbtns.Add(ScoreOpt2);
            ChildRbtns.Add(ScoreOpt3);
            ChildRbtns.Add(ScoreOpt4);
            ChildRbtns.Add(ScoreOpt5);

            ConnectionStatusDot.Image = dots[0];

            foreach (var rbtn in RootRbtns) 
            {
                rbtn.CheckedChanged += new EventHandler(OnRootCheck);
                rbtn.Checked = false;
            }

            foreach (var rbtn in ChildRbtns) 
            {
                rbtn.CheckedChanged += new EventHandler(OnChildCheck);
                rbtn.Checked = false;
            }

            SendScoreButton.Click += new EventHandler(OnSendButton);

            OptScorePanel.LocationChanged += new EventHandler(OnChildPanelChange);

            MainPanel.Show();

            CurrentScoreBox.Font = new System.Drawing.Font(CurrentScoreBox.Font.FontFamily, 26, FontStyle.Bold);
            CurrentScoreBox.TextAlign = HorizontalAlignment.Center;
            CurrentScoreBox.TextChanged += new EventHandler(OnCurrentScoreBoxTextChange);

            constantWorker.DoWork += new DoWorkEventHandler(ConstantWorkerWork);
            constantWorker.ProgressChanged += new ProgressChangedEventHandler(ConstantWorkerReporting);
            constantWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(ConstantWorkerCompleted);

            connectWorker.DoWork += new DoWorkEventHandler(ConnectWorkerWork);
            connectWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(ConnectWorkerCompleted);

            constantWorker.WorkerSupportsCancellation = true;
            constantWorker.WorkerReportsProgress = true;

            DiveBox.TextAlign = ContentAlignment.TopCenter;

            judge.FormClosed += new FormClosedEventHandler(OnJudgeClose);


            ScoreRootPanel.Enabled = false;
            SendScoreButton.Enabled = false;

            LayoutMouse.VisibleChanged += new EventHandler(OnLayoutMouseVisible);
            LayoutKeyboard.VisibleChanged += new EventHandler(OnLayoutKeyboardVisible);
            LayoutMouse.Hide();
            LayoutKeyboard.Hide();

            OptScorePanel.Hide();

            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;

            CurrentScoreBox.KeyDown += new KeyEventHandler(CheckIfEneterHit);
        }

        private void CheckIfEneterHit(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Return && this.CurrentScoreBox.Text != "") 
            {
                SendScoreButton.PerformClick();
            }
        }

        private void OnCurrentScoreBoxTextChange(object sender, EventArgs e) 
        {
            TextBox tb = (TextBox)sender;
            char[] validCommaDigits = { '0', '5' };

            if (tb.Text.Length > 0) 
            {
                if (char.IsDigit(tb.Text[0]))
                {
                    if (tb.Text.Length >= 2)
                    {
                        if (char.IsPunctuation(tb.Text[1]))
                        {
                            if (tb.Text.Length >= 3)
                            {
                                if (validCommaDigits.Contains(tb.Text[2]))
                                {
                                    if (tb.Text.Length > 3) 
                                    {
                                        tb.Text = tb.Text.Remove(3);
                                        tb.Select(tb.Text.Length, 0);
                                    }
                                    return;
                                }
                                else
                                {
                                    tb.Text = tb.Text.Remove(2);
                                    tb.Select(tb.Text.Length, 0);
                                    return;
                                }
                            }
                        }
                        else
                        {
                            if (tb.Text[0] == '1' && tb.Text[1] == '0')
                            {
                                if (tb.Text.Length >= 3) 
                                {
                                    tb.Text = tb.Text.Remove(2);
                                    tb.Select(tb.Text.Length, 0);
                                }
                                return;
                            }
                            else
                            {
                                tb.Text = tb.Text.Remove(1);
                                tb.Select(tb.Text.Length, 0);
                                return;
                            }
                        }
                    }
                }
                else 
                {
                    tb.Text = tb.Text.Remove(0);
                    tb.Select(tb.Text.Length, 0);
                    return;
                }
            }

            for (int i = 0; i < tb.Text.Length; i++)
            {
                if (char.IsLetter(tb.Text[i]) || char.IsSymbol(tb.Text[i])) 
                {
                    tb.Text = tb.Text.Remove(i);
                    tb.Select(tb.Text.Length, 0);
                    return;
                }            
            }
        }

        private void OnLayoutKeyboardVisible(object sender, EventArgs e)
        {
            if (LayoutKeyboard.Visible) 
            {
                LayoutKeyboard.Controls.Add(JudgeIDLabel);
                LayoutKeyboard.Controls.Add(JudgeNameLabel);
                LayoutKeyboard.Controls.Add(ConnectionStatusDot);
                LayoutKeyboard.Controls.Add(ConnectionInfoLabel);
                LayoutKeyboard.Controls.Add(SendScoreButton);
                LayoutKeyboard.Controls.Add(CurrentScoreBox);
                LayoutKeyboard.Controls.Add(DiveBox);

                CurrentScoreBox.Location = new Point(17, 99);
                CurrentScoreBox.ReadOnly = false;
                CurrentScoreBox.Enabled = true;

                SendScoreButton.Location = new Point(257, 99);

                JudgeNameLabel.Location = new Point(97, 173);

                JudgeIDLabel.Location = new Point(97, 203);

                ConnectionStatusDot.Location = new Point(327, 177);

                ConnectionInfoLabel.Location = new Point(323, 203);

                this.Size = new System.Drawing.Size(orignSize.Width, 270);

                LayoutMouse.Hide(); 
            }
        }

        private void OnLayoutMouseVisible(object sender, EventArgs e)
        {
            if (LayoutMouse.Visible)
            {
                MainPanel.Controls.Add(JudgeIDLabel);
                MainPanel.Controls.Add(JudgeNameLabel);
                MainPanel.Controls.Add(ConnectionStatusDot);
                MainPanel.Controls.Add(ConnectionInfoLabel);
                MainPanel.Controls.Add(DiveBox);
                LayoutMouse.Controls.Add(SendScoreButton);
                LayoutMouse.Controls.Add(CurrentScoreBox);

                this.Size = this.orignSize;

                LayoutKeyboard.Hide();

                CurrentScoreBox.Location = new Point(7, 67);
                CurrentScoreBox.ReadOnly = true;
                CurrentScoreBox.Enabled = false;

                SendScoreButton.Location = new Point(245, 67);

                JudgeNameLabel.Location = new Point(97, 239);

                JudgeIDLabel.Location = new Point(97, 268);

                ConnectionInfoLabel.Location = new Point(323, 268);

                ConnectionStatusDot.Location = new Point(327, 242);
            }
        }

        private void OnJudgeClose(object sender, FormClosedEventArgs e)
        {
            this.Enabled = true;
            if (judge.DialogResult == System.Windows.Forms.DialogResult.OK)
            {
                if (EventGetJudgeLayout != null)
                {
                    if (EventGetJudgeLayout() == "Mouse")
                    {
                        LayoutMouse.Show();
                        mouseToolStripMenuItem.Checked = true;
                        keyboardToolStripMenuItem.Checked = false;
                    }
                    else if (EventGetJudgeLayout() == "Keyboard")
                    {
                        LayoutKeyboard.Show();
                        keyboardToolStripMenuItem.Checked = true;
                        mouseToolStripMenuItem.Checked = false;
                    }

                    if (!connectWorker.IsBusy) 
                    {
                        connectWorker.RunWorkerAsync();
                    }
                }
            }
        }

        private void helpToolStripMenuItem_Click(object sender, EventArgs e)
        {
            
        }

        private void NewJudgeItem_Click(object sender, EventArgs e)
        {
            this.Enabled = false;
            judge.ShowDialog(this);
        }

        private void mouseToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!LayoutMouse.Visible)
            {
                LayoutMouse.Show();
            }
            else 
            {
                LayoutMouse.Hide();
            }
            keyboardToolStripMenuItem.Checked = false;
        }

        private void keyboardToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!LayoutKeyboard.Visible)
            {
                LayoutKeyboard.Show();
            }
            else
            {
                LayoutKeyboard.Hide();
            }
            mouseToolStripMenuItem.Checked = false;
        }

        private void OnSendButton(object sender, EventArgs e) 
        {
            if (this.CurrentScoreBox.Text != "")
            {
                DialogResult result;

                result = MessageBox.Show(this, "Are you sure you want to send:\n" + CurrentScoreBox.Text + "?", "Send score", MessageBoxButtons.YesNo);


                if (result == System.Windows.Forms.DialogResult.Yes)
                {
                    if (EventSend != null && EventGetJudgeID != null && EventGetDiveOrder != null)
                    {
                        EventSend(EventGetJudgeID() + "," + CurrentScoreBox.Text.Replace(',', '.'));
                        SendScoreButton.Enabled = false;
                        SendScoreButton.Text = "Waiting for dive...";
                        ScoreRootPanel.Enabled = false;
                        OptScorePanel.Enabled = false;

                        string[] diverOrder = EventGetDiveOrder().Split('/');

                        if (diverOrder[0] != "0" && diverOrder[1] != "0" && diverOrder[0] == diverOrder[1])
                        {
                            if (constantWorker.IsBusy)
                            {
                                this.ConnectionInfoLabel.Text = "Contest done!";
                                this.DiveBox.Text = "";
                            }
                        }
                    }
                }
            }
        }

        private void OnChildCheck(object sender, EventArgs e)
        {
            RadioButton rbtn = (RadioButton)sender;
            CurrentScoreBox.Text = rbtn.Text;
        }

        private void OnChildPanelChange(object sender, EventArgs e)
        {
            if (ScoreRoot7.Checked == false && ScoreRoot1.Checked == false) 
            {
                ScoreOpt1.Checked = true;
                ScoreOpt1.Checked = false;
                ScoreOpt1.Checked = true;
            }
        }

        private void OnRootCheck(object sender, EventArgs e) 
        {
            RadioButton rbtn = (RadioButton)sender;

            if (rbtn.Name.Contains('1') == false && rbtn.Name.Contains('7') == false)
            {
                SetScoreOptInRbtns(rbtn.Text.Split('-')[0]);
                if (rbtn.Name == "ScoreRoot3")
                {
                    ScoreOpt5.Show();
                    ScoreOpt4.Show();
                }
                else if (rbtn.Name == "ScoreRoot5" || rbtn.Name == "ScoreRoot6") 
                {
                    ScoreOpt5.Hide();
                    ScoreOpt4.Hide();
                }
                else
                {
                    ScoreOpt5.Hide();
                    ScoreOpt4.Show();
                }
                OptScorePanel.Show();
            }
            if(rbtn.Name.Contains('1') || rbtn.Name.Contains('7'))
            {
                OptScorePanel.Hide();
                CurrentScoreBox.Text = rbtn.Text;
            }
            OptScorePanel.Location = new Point(((LayoutMouse.Size.Width / 2) - ((40 * CountActiveChildren()) / 2)) - 10, OptScorePanel.Location.Y);
        }

        private void ExitItem_Click(object sender, EventArgs e)
        {
            DialogResult result;

            result = MessageBox.Show(this, "Are you sure you want to exit?", "Exit", MessageBoxButtons.YesNo);
            if (result == System.Windows.Forms.DialogResult.Yes)
            {
                this.Close();
            }
        }

        private int CountActiveChildren() 
        {
            int returnInt = 0;
            foreach (var rbtn in ChildRbtns) 
            {
                if (rbtn.Visible) 
                {
                    returnInt++;   
                }
            }
            return returnInt;
        }

        private void SetScoreOptInRbtns(string start) 
        {
            for(int i = 0; i < ChildRbtns.Count; i++)
            {
                ChildRbtns[i].Text = (((float.Parse(start) + 0.5 * i).ToString()).PadRight(2,',')).PadRight(3, '0');
            }
        }

        private void ConnectWorkerWork(object sender, DoWorkEventArgs e) 
        {
            BackgroundWorker worker = (BackgroundWorker)sender;

            while (true) 
            {
                if (EventGetIsConnected != null) 
                {
                    if (EventGetIsConnected())
                    {
                        break;
                    }
                    else if(EventConnectToServer != null)
                    {
                        EventConnectToServer();
                        System.Threading.Thread.Sleep(500);
                    }
                }
            }
        }

        private void ConnectWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
        {
            if (!(e.Error == null))
            {
                System.Console.WriteLine("An error with Connectworker occured");
            }
            else
            {
                System.Console.WriteLine("ConnectWorkercomplete!");
                if (!constantWorker.IsBusy) 
                {
                    this.JudgeIDLabel.Text = EventGetJudgeID().ToString();
                    this.constantWorker.RunWorkerAsync();
                }
            }
        }

        private void ConstantWorkerWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = (BackgroundWorker)sender;

            while (true) 
            {
                if (worker.CancellationPending)
                {
                    e.Cancel = true;
                    break;
                }
                else 
                {
                    if (EventGetIsReceivedNewData != null)
                    {
                        if (EventGetIsReceivedNewData())
                        {
                            worker.ReportProgress(0);
                        }
                    }

                    if (EventGetIsConnected != null)
                    {
                        if (!EventGetIsConnected())
                        {
                            e.Cancel = true;
                            break;
                        }
                        else if (EventGetJudgeName != null && EventGetJudgeID != null && EventSend != null) 
                        {
                            if (EventGetJudgeName() == "") 
                            {
                                EventSend(":" + EventGetJudgeID());
                            }
                        }
                    }
                    System.Threading.Thread.Sleep(1000);
                }
            }
        }

        private void ConstantWorkerReporting(object sender, ProgressChangedEventArgs e)
        {
            System.Console.WriteLine("Constant worker reporting");
            BackgroundWorker worker = (BackgroundWorker)sender;

            if(EventGetJudgeName != null && EventGetDiveCode != null && EventSetIsReceivedNewData != null && EventGetDiveOrder != null)
            {
                this.DiveBox.Text = EventGetDiveCode();
                this.ConnectionInfoLabel.Text = EventGetDiveOrder();
                this.EventSetIsReceivedNewData(false);
                this.ConnectionStatusDot.Image = dots[1];

                if (EventGetDiveCode() != "")
                {
                    this.SendScoreButton.Enabled = true;
                    this.SendScoreButton.Text = "Send Score";
                }

                this.ScoreRootPanel.Enabled = true;
                this.OptScorePanel.Enabled = true;
                this.JudgeNameLabel.Text = EventGetJudgeName();
                this.CurrentScoreBox.Text = "";

                if (this.JudgeNameLabel.Text.ToLower() == "none") 
                {
                    MessageBox.Show(this, "An invalid Judge ID was given!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                    worker.CancelAsync();
                }
            }
        }

        private void ConstantWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            BackgroundWorker worker = (BackgroundWorker)sender;
            if (e.Cancelled == true)
            {
                System.Console.WriteLine("Server disconnect!");
                this.ConnectionInfoLabel.Text = "Server disconnect.";
                this.ConnectionStatusDot.Image = dots[0];
                try
                {
                    if (EventSetJudgeName != null)
                    {
                        EventSetJudgeName("");
                        this.JudgeNameLabel.Text = "";
                        this.JudgeIDLabel.Text = "";
                        judge.ShowDialog();
                        return;
                    }
                }
                catch (InvalidOperationException) 
                {
                    return;
                }
            }
            else if (!(e.Error == null))
            {
                System.Console.WriteLine("An error with ConstantWorker occured");
            }
            else
            {
                System.Console.WriteLine("ConstantWorker complete!");
            }
        }

        public event DelegateSetIsReceivedNewData EventSetIsReceivedNewData = null;

        public event DelegateGetIsReceivedNewData EventGetIsReceivedNewData = null;

        public event DelegateSetEmptyDiveCode EventSetEmptyDiveCode = null;

        public event DelegateGetIsConnected EventGetIsConnected = null;

        public event DelegateSend EventSend = null;

        public event DelegateConnectToServer EventConnectToServer = null;

        public event DelegateGetDiveCode EventGetDiveCode = null;

        public event DelegateGetJudgeName EventGetJudgeName = null;

        public event DelegateGetJudgeID EventGetJudgeID = null;

        public event DelegateSetJudgeName EventSetJudgeName = null;

        public event DelegateGetJudgeLayout EventGetJudgeLayout = null;

        public event DelegateGetDiveOrder EventGetDiveOrder = null;
    }
}
